package demo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import demo00.W0_MyCallable;
import demo01.W1_Cooker;
import demo01.W1_Desk;
import demo01.W1_Fooide;
import demo02.W2_Mythread;
import demo03.W3_FizzBuzz;
import demo04.W4_LetterRunnable;
import demo04.W4_NumberRunnable;
import demo04.W4_SynchMethod;
import demo05.W5_FileCopy;
import demo06.W6_DeclineJ;
import demo06.W6_IncreaseJ;
import demo06.W6_ShareJ;
import demo07.W7_ZeroEvenOdd;

public class Demo {
	public static void main(String[] args) throws Exception, Exception {

		/*	0000000000000000000000
		 * 抽奖箱作业：
		 * 	打印出总额和最大值
		 * 	抽奖箱1中了  800 100 1000 20 80 10 总额为
		 * 	抽奖箱2中了  5 300 200 50 550 2 总额为
		 * 	再加上，在此次抽奖过程中，抽奖箱1，产生了最大得金额，1000元
		 */

		/*//1.创建集合，存放所有抽奖奖项
		ArrayList<Integer> list=new ArrayList<>();
		Collections.addAll(list, 10,5,20,50,100,200,550,800,2,80,300,1000);

		//2.抽奖箱1线程
		W0_MyCallable mc1=new W0_MyCallable(list);
		FutureTask<ArrayList<Integer>> ft1=new FutureTask<>(mc1);
		Thread m1 = new Thread(ft1);
		m1.setName("抽奖箱1");
		m1.start();

		//3.抽奖箱2线程
		W0_MyCallable mc2=new W0_MyCallable(list);
		FutureTask<ArrayList<Integer>> ft2=new FutureTask<>(mc2);
		Thread m2 = new Thread(ft2);
		m2.setName("抽奖箱2");
		m2.start();

		//4.取出抽奖箱1集合，打印最大金额和总额
		ArrayList<Integer> list1 = ft1.get();
		Integer max1 = list1.stream().max(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o1-o2;
			}
		}).get();
		int sum1 = list1.stream().reduce(0, Integer::sum);
		System.out.println(m1.getName()+"产生的最大金额为"+max1+"，总额为"+sum1);

		//5.取出抽奖箱2集合，打印最大金额和总额
		ArrayList<Integer> list2 = ft2.get();
		Integer max2 = list2.stream().max(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o1-o2;
			}
		}).get();
		int sum2 = list1.stream().reduce(0, Integer::sum);
		System.out.println(m2.getName()+"产生的最大金额为"+max2+"，总额为"+sum2);*/




		/*	1111111111111111111111
		 * 作业一：生产5个 消费5个
		 */

		/*//1.创建Desk对象
		W1_Desk d=new W1_Desk();
		W1_Fooide f=new W1_Fooide(d);
		W1_Cooker c=new W1_Cooker(d);
		f.start();
		c.start();*/




		/*	222222222222222222222222
		 * 作业二：子进程先执行三次，主进程再执行五次，然后这个过程执行三次
		 */

		//方法一：
		/*//1.for循环对整个过程执行3次
		for(int i=0;i<3;i++){
			//2.创建子线程，打印三次
			Thread Zi = new Thread(()->{
				printNumber(3,"子进程");
			});
			//3.创建主线程，打印五次
			Thread Zhu = new Thread(()->{
				try {
					//Zhu等待Zi执行
					Zi.join();
				} catch (InterruptedException e) {
				}
				printNumber(5,"主进程");
			});
			System.out.println("第"+(i+1)+"次循环");
			//4.执行线程
			Zi.start();
			Zhu.start();

			try {  
				//5.在外部循环中等待父线程完成，再进行下一次循环
				Zhu.join();  
			} catch (InterruptedException e) {  
				e.printStackTrace();  
			}  
		}*/

		//方法二：
		/*//1.for循环对整个过程执行3次
		for(int i=0;i<3;i++){
			System.out.println("第"+(i+1)+"次循环");
			//2.创建子线程，执行
			W2_Mythread Zi = new W2_Mythread();
			Zi.start();
			//3.主线程for循环执行5次
			for(int j=0;j<5;j++){
				Zi.join();
				System.out.println("主进程执行第"+(j+1)+"次");
			}
		}*/




		/* 33333333333333333333333333
		 * 作业三：编写一个可以从 1 到 n 输出代表这个数字的字符串的程序
		 * 输入n
		 * 如果这个数字可以被 3 整除，输出 "fizz"。
		 * 如果这个数字可以被 5 整除，输出 "buzz"。
		 * 如果这个数字可以同时被 3 和 5 整除，输出 "fizzbuzz"。
		 * 例如，当 n = 15，输出： 1, 2, fizz, 4, buzz, fizz, 7, 
		 *     8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz
		 */

		/*//1.数字n
		int n=15;
		//2.创建线程
		W3_FizzBuzz fizzBuzz = new W3_FizzBuzz(n);
		Thread threadA = new Thread(() -> fizzBuzz.fizz());
		Thread threadB = new Thread(() -> fizzBuzz.buzz());
		Thread threadC = new Thread(() -> fizzBuzz.fizzbuzz());
		Thread threadD = new Thread(() -> fizzBuzz.number());
		//3.执行线程
		threadA.start();
		threadB.start();
		threadC.start();
		threadD.start();
		try {
			threadA.join();
			threadB.join();
			threadC.join();
			threadD.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/




		/*	44444444444444444444444444
		 * 作业四：写两个线程，一个线程打印1~ 52，另一个线程打印A~Z，打印顺序是12A34B…5152Z
		 */

		/*//1.同步方法
		W4_SynchMethod printer = new W4_SynchMethod();
		//2.创建线程
        Thread numberThread = new Thread(new W4_NumberRunnable(printer));
        Thread letterThread = new Thread(new W4_LetterRunnable(printer));
        //3.开启线程
        numberThread.start();
        letterThread.start();
		 */



		/*	5555555555555555555555555555
		 * 作业五：使用多线程实现多个文件同步复制功能，并在控制台显示复制的进度，进度以百分比表示。
		 * 例如：把文件A复制到E盘某文件夹下，在控制台上显示“XXX文件已复制10%”，
		 * “XXX文件已复制20%”……“XXX文件已复制100%”，“XXX复制完成！”
		 * A文件复制了10%
		 * A文件复制了20%
		 * B文件复制10%
		 * A文件复制30%
		 * C文件复制10%
		 */

		/* //1.文件源路径和目标路径字符串
        String sourceDir = "d:\\aa";  
        String targetDir = "d:\\copy";  
        //2.创建一个固定大小的线程池  
        ExecutorService executorService = Executors.newFixedThreadPool(5);  
        //3.创建对象
        W5_FileCopy fileCopier = new W5_FileCopy();  

        try {  
        	//4.调用方法，提交文件复制任务给线程池
            fileCopier.copyDirectory(new File(sourceDir), new File(targetDir), executorService);  
            //5.关闭线程池
            executorService.shutdown();  
            //6.如果线程池还没有关闭，或者虽然已经关闭但还有任务没有完成
            while (!executorService.isTerminated()) {  
                //等待线程池中的任务都执行完毕  
            }  
            System.out.println("文件夹复制完成！");  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            //7.无论是否发生异常，都尝试关闭线程池  
            executorService.shutdownNow();
        }*/




		/*	666666666666666666666
		 * 作业六：设计4个线程，其中两个线程每次对j增加1，另外两个线程对j每次减少1。
		 * 	  考虑到线程的安全性写出程序。（不要使用atomaicInteger 来做）
		 */

		/*//1.创建共享变量j
		W6_ShareJ j = new W6_ShareJ();  
		//2.创建两个增加线程  
		Thread increse1 = new W6_IncreaseJ(j); 
		increse1.setName("j++线程一");
		Thread increse2 = new W6_IncreaseJ(j);  
		increse2.setName("j++线程二");
		//3.创建两个减少线程  
		Thread decline1 = new W6_DeclineJ(j);
		decline1.setName("j--线程三");
		Thread decline2 = new W6_DeclineJ(j);  
		decline2.setName("j--线程四");
		//4.启动线程  
		increse1.start();  
		increse2.start();  
		decline1.start();  
		decline2.start();  
		//5.插入线程
		try {  
			increse1.join();  
			increse2.join();  
			decline1.join();  
			decline2.join();  
		} catch (InterruptedException e) {  
			e.printStackTrace();  
		}  

		//6.打印最终值  
		System.out.println("j的最终值: " + j.getJ());*/
		
		
		
		
		/*	77777777777777777777777777
		 * 作业七：现有函数 printNumber 可以用一个整数参数调用，并输出该整数到控制台。
			例如，调用 printNumber(7) 将会输出 7 到控制台。

			给你类 ZeroEvenOdd 的一个实例，该类中有三个函数：zero、even 和 odd 。ZeroEvenOdd 的相同实例将会传递给三个不同线程：
			线程 A：调用 zero() ，只输出 0
			线程 B：调用 even() ，只输出偶数
			线程 C：调用 odd() ，只输出奇数
			修改给出的类，以输出序列 "010203040506..." ，其中序列的长度必须为 2n 。

			实现 ZeroEvenOdd 类：
			ZeroEvenOdd(int n) 用数字 n 初始化对象，表示需要输出的数。
			void zero(printNumber) 调用 printNumber 以输出一个 0 。
			void even(printNumber) 调用printNumber 以输出偶数。
			void odd(printNumber) 调用 printNumber 以输出奇数。
		 
			示例 1：
			输入：n = 2
			输出："0102"
			解释：三条线程异步执行，其中一个调用 zero()，另一个线程调用 even()，最后一个线程调用odd()。正确的输出为 "0102"。
			示例 2：
			输入：n = 5
			输出："0102030405"
		 */
		
		int n = 7;
        W7_ZeroEvenOdd zeroEvenOdd = new W7_ZeroEvenOdd(n);
        //1.线程zero，只输出 0
        Thread zeroThread = new Thread(() -> {
            try {
                zeroEvenOdd.zero();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //2.线程even，只输出偶数
        Thread evenThread = new Thread(() -> {
            try {
                zeroEvenOdd.even();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //3.线程odd，只输出奇数
        Thread oddThread = new Thread(() -> {
            try {
                zeroEvenOdd.odd();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //4.启动线程
        zeroThread.start();
        evenThread.start();
        oddThread.start();
        //5.插入线程
        try {
            zeroThread.join();
            evenThread.join();
            oddThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
	}

	private static void printNumber(int j, String threadName){
		int i=0;
		while(i++<j){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(threadName+"print:"+i);
		}
	}
}

